Summary
object-observer
provides a deep observation of a changes performed on an object/array graph.
Main aspects:
- implemented via native Proxy (revokable)
- observation is 'deep', yielding changes from a sub-graphs too
- changes delivered in a synchronous way
- original objects are cloned while turned into
Observable
s - arrays specifics:
- generic object-like mutations supported
- intrinsic
Array
mutation methods supported: pop
, push
, shift
, unshift
, reverse
, sort
, fill
, splice
- massive mutations delivered in a single callback, usually having an array of an atomic changes
- intrinsic mutation methods of
Map
, WeakMap
, Set
, WeakSet
(set
, delete
) etc are not observed (see this issue for more details) - following host objects are not observed, but left as they are:
Date
, Blob
, Number
, String
, Boolean
, Error
, SyntaxError
, TypeError
, URIError
, Function
, Promise
, RegExp
Support matrix: 49+ | 42+ | 13+ | 8.10.0+
ES6 module flavor distribution of the library have a higher versions in it's browser support matrix: Chrome 61, FireFox 60 and Edge 16.
Performance report can be found here
Last versions (full changelog is here)
-
1.2.0
-
1.1.5
- implemented improvement as suggested in Issue no. 13
- added tests to CI + coverage report
-
1.1.4
- added
object
property to the Change
pointing the the immediate subject of change; Issue no. 12. Attention: this change is found only in ES6-module flavor distribution.
For a short preview you may want to play with this JSFiddle.
Loading the Library
You have few ways to load the library: as an ES6 module (pay attention to the module
/ node-module
in the path) or as a regular script (into a 'window' global scope, or a custom scope provided by you). See examples below.
Attention: in some (observable :-)) future non-module syntax flavor will be frozen in a stable state and only defect fixes will be done there.
Active development will focus on the ES6 module code base, which is effectively raising the support matrix of Chrome to 61, FireFox to 60 and Edge to 16.
import Observable from 'dist/module/object-observer.min.js';
let Observable = require('./dist/node-module/object-observer');
- Simple a reference (script tag) to the
object-observer.min.js
/object-observer.js
in your HTML
will load it into the global scope:
<script src="dist/object-observer.min.js"></script>
<script>
let person = { name: 'Uria', age: 8 },
observablePerson;
observablePerson = Observable.from(person);
</script>
- Following loader exemplifies how to load the library into a custom scope (add error handling as appropriate):
let customNamespace = {},
person = { name: 'Nava', age: 6 },
observablePerson;
fetch('dist/object-observer.min.js').then(function (response) {
if (response.status === 200) {
response.text().then(function (code) {
Function(code).call(customNamespace);
observablePerson = customNamespace.Observable.from(person);
});
}
});
API
Library implements Observable
API as it is defined here.
Examples
Objects
let order = { type: 'book', pid: 102, ammount: 5, remark: 'remove me' },
observableOrder = Observable.from(order);
observableOrder.observe(changes => {
changes.forEach(change => {
console.log(change);
});
});
observableOrder.ammount = 7;
observableOrder.address = {
street: 'Str 75',
apt: 29
};
observableOrder.address.apt = 30;
delete observableOrder.remark;
Arrays
let a = [ 1, 2, 3, 4, 5 ],
observableA = Observable.from(a);
observableA.observe(changes => {
changes.forEach(change => {
console.log(change);
});
});
observableA.pop();
observableA.push('a', 'b');
observableA.shift();
observableA.unshift('x', 'y');
observableA.reverse();
observableA.sort();
observableA.fill(0, 0, 1);
observableA.splice(0, 1, 'x', 'y');
let customer = { orders: [ ... ] },
oCustomer = Observable.from(customer);
oCustomer.orders.sort();
oCustomer.orders.reverse();
Arrays notes: Some of array operations are effectively moving/reindexing the whole array (shift, unshift, splice, reverse, sort).
In cases of massive changes touching presumably the whole array I took a pessimistic approach with a special non-detailed events: 'reverse' for reverse
, 'shuffle' for sort
. The rest of these methods I'm handling in an optimistic way delivering the changes that are directly related to the method invocation, while leaving out the implicit outcomes like reindexing of the rest of the Array.